﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Devv.Core.Erroo;
using Devv.Core.Utils;
using Devv.FreshTracker.Entity;
using Devv.FreshTracker.Properties;

namespace Devv.FreshTracker
{
	public partial class MainForm : Form
	{
		#region Public properties

		public MiniForm Mini { get; set; }

		#endregion

		#region Internal properties

		private Boolean ForceClose { get; set; }
		private Int32 EscCount { get; set; }
		private Int32 NoteCountdown { get; set; }

		#endregion

		#region Main methods

		public MainForm()
		{
			InitializeComponent();
			ForceClose = false;
		}

		private void MainForm_Load(object sender, EventArgs e)
		{
			Text = ConfigUtil.GetConfig("Devv.AppName");

			Icon = Resources.App;
			TopMost = Options.TopMost;

			trayIcon.Icon = Resources.App;
			trayMenuTopMost.Checked = Options.TopMost;
			trayMenuDonate.Visible = String.IsNullOrEmpty(App.LicensedTo);

			Application.ThreadException += ErrorHandler.OnThreadException;

			SessionTimer.ThreadSync(this);
			SessionTimer.OnTimerTick += TimerTick;
			SessionTimer.OnTimerAutoStop += TimerAutoStopped;

			SetPosition();
			SetAutoTracking();

			ThreadPool.QueueUserWorkItem(Maintenance.Run);

			if (CheckLogin())
			{
				RefreshLocalCache();
			}
		}

		private void MainForm_LocationChanged(object sender, EventArgs e)
		{
			Options.PosX = Left;
			Options.PosY = Top;
		}

		private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			Boolean donate = Options.FirstRun;

			HideFromUser();

			if (!ForceClose)
			{
				e.Cancel = true;

				if (Options.ShowMini)
				{
					ShowMini();
				}
			}
			else
			{
				Program.Closing = true;
				Options.FirstRun = false;

				try
				{
					SessionTimer.ThreadSync(null); 
					AutoTracking.Stop();
					
					if (AutoTracking.HasSessionsToUpload)
					{
						if (Options.ShowNotes && MessageBox.Show(Messages.AutoTrackingConfirmToUpload, Messages.Confirm, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
						{
							e.Cancel = true;

							Program.ShowRulesForm(true);
						}
						else
						{
							AutoTracking.Save();
						}
					}
				}
				catch (Exception ex)
				{
					ErrorHandler.Handle(ex);
				}
			}

			if (!e.Cancel)
			{
				String version = AssemblyUtil.GetFriendlyVersion(Assembly.GetEntryAssembly());

				if (String.IsNullOrEmpty(App.LicensedTo) && (donate || version != Options.CurrentVersion))
				{
					using (DonateForm form = new DonateForm())
					{
						form.ShowDialog();
					}

					Options.CurrentVersion = version;
				}

				Options.Save();
				Maintenance.Log("APP CLOSED!", true);

				trayIcon.Dispose();
			}
		}

		private void MainForm_Activated(object sender, EventArgs e)
		{
			Opacity = Options.Opacity;

			StringBuilder tip = new StringBuilder();
			tip.Append(Messages.AutoTracking + ": ");

			if (Options.EnableRules)
			{
				tip.Append(Messages.Enabled);

				foreach (Session s in AutoTracking.Sessions)
				{
					tip.Append(Environment.NewLine);
					tip.Append(s.Task.FullDisplayMember + " (" + s.GetHoursFromTempSeconds().ToString("00:00") + ")");
				}
			}
			else
			{
				tip.Append(Messages.Disabled);
			}

			tip.Append(Environment.NewLine);
			tip.Append(Environment.NewLine);
			tip.Append(Messages.ClickToOpenRules);

			toolTips.SetToolTip(imgAuto, tip.ToString());
		}

		private void MainForm_Deactivate(object sender, EventArgs e)
		{
			if (Options.TopMost && !Program.Closing)
			{
				Opacity = Options.Opacity * 0.8;
			}
		}

		private void MainForm_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
		{
			if (e.KeyCode == Keys.Escape)
			{
				if (SessionTimer.Running)
				{
					TimerPause();
				}
				else
				{
					TimerReset();
				}

				if (EscCount > 4)
				{
					TimerReset();
					EscCount = 0;
				}

				EscCount++;
			}
			else
			{
				EscCount = 0;
			}
		}

		private Boolean CheckLogin()
		{
			Boolean result;

			if (!Options.IsLoginSet)
			{
				if (!Options.FirstRun)
				{
					MessageBox.Show(Messages.WarningLoginNotSet, Messages.LoginDetails, MessageBoxButtons.OK, MessageBoxIcon.Information);
					Program.ShowOptionsForm();
				}

				result = Options.UserId > 0;
			}
			else
			{
				result = true;
			}

			cboProjects.Enabled = result;
			cboTasks.Enabled = result;
			panSave.Enabled = result;
			
			return result;
		}

		private void SetPosition()
		{
			Int32 x = Options.PosX;
			Int32 y = Options.PosY;

			Screen screen = Screen.FromRectangle(new Rectangle(x, y, Width, Height));
			Int32 maxLeft = screen.WorkingArea.Width - Width - 10;
			Int32 maxTop = screen.WorkingArea.Height - Height - 10;

			if (x < 1)
			{
				x = maxLeft;
			}

			if (y < 1)
			{
				y = maxTop;
			}

			Left = x > maxLeft ? maxLeft : x;
			Top = x > maxTop ? maxTop : y;
		}

		public void ShowToUser()
		{
			Show();
			BringToFront();

			WindowState = FormWindowState.Normal;

			CloseMini();
		}

		public void HideFromUser()
		{
			Hide();
			WindowState = FormWindowState.Minimized;
		}

		#endregion

		#region Mini form

		public void ShowMini()
		{
			if (panNotes.Visible)
			{
				SessionTimer.Save(txtNote.Text);
			}

			if (Mini != null)
			{
				Mini.Dispose();
			}

			Mini = new MiniForm();
			Mini.Show();

			HideFromUser();
		}

		public void CloseMini()
		{
			if (Mini != null)
			{
				Mini.Close();
				Mini.Dispose();
			}
		}

		#endregion

		#region Options and rules

		private void imgAuto_Click(object sender, EventArgs e)
		{
			Program.ShowRulesForm();
		}

		private void imgOptions_Click(object sender, EventArgs e)
		{
			Program.ShowOptionsForm();

			ShowToUser();
		}

		public void SetAutoTracking()
		{
			if (Options.EnableRules)
			{
				imgAuto.Image = Resources.IcoAutomaticOn16;
				toolTips.SetToolTip(imgAuto, Messages.AutoTracking + ": " + Messages.Enabled);
			}
			else
			{
				imgAuto.Image = Resources.IcoAutomaticOff16;
				toolTips.SetToolTip(imgAuto, Messages.AutoTracking + ": " + Messages.Disabled);
			}
		}

		#endregion

		#region Clients, projects, tasks

		private void cboProjects_DropDown(object sender, EventArgs e)
		{
			cboProjects.DisplayMember = "DisplayMember";

			Application.DoEvents();
		}

		private void cboProjects_DropDownClosed(object sender, EventArgs e)
		{
			cboProjects.DisplayMember = "Name";

			Application.DoEvents();
		}

		private void cboProjects_SelectionChangeCommitted(object sender, EventArgs e)
		{
			SetCurrentProject();
		}

		private void cboTasks_SelectionChangeCommitted(object sender, EventArgs e)
		{
			if (cboTasks.SelectedIndex < 0) return;

			Options.LastTaskId = ((Task)cboTasks.SelectedItem).Id;
		}

		private void SetCurrentProject()
		{
			Project p = (Project)cboProjects.SelectedItem;

			if (cboProjects.SelectedIndex >= 0)
			{
				cboTasks.Enabled = true;
				cboTasks.DataSource = LocalCache.GetTasks(p);
			}

			for (var i = 0; i < cboTasks.Items.Count; i++)
			{
				if (((Task)cboTasks.Items[i]).Id == Options.LastTaskId)
				{
					cboTasks.SelectedIndex = i;
					break;
				}
			}

			lblCurrentClient.Text = p.Client.DisplayMember;
			cboProjects.DisplayMember = "Name";
			cboProjects.SelectedItem = p;
			cboTasks.Enabled = true;

			Options.LastProjectId = p.Id;

			Application.DoEvents();
		}

		#endregion

		#region Time tracking

		private void lblTime_DoubleClick(object sender, EventArgs e)
		{
			if (SessionTimer.Running)
			{
				TimerPause();
			}
			else
			{
				TimerStart();
			}
		}

		private void panelButton_MouseEnter(object sender, EventArgs e)
		{
			String n = ((Control)sender).Name.Substring(3);
			Label lbl = Controls.Find("lbl" + n, true)[0] as Label;

			if (lbl != null)
			{
				lbl.ForeColor = SystemColors.HotTrack;
			}
		}

		private void panelButton_MouseLeave(object sender, EventArgs e)
		{
			String n = ((Control)sender).Name.Substring(3);
			Label lbl = Controls.Find("lbl" + n, true)[0] as Label;

			if (lbl != null)
			{
				lbl.ForeColor = SystemColors.ControlText;
			}
		}

		private void butStart_Click(object sender, EventArgs e)
		{
			TimerStart();
		}

		private void butPause_Click(object sender, EventArgs e)
		{
			TimerPause();
		}

		private void butSave_Click(object sender, EventArgs e)
		{
			TimerSave();
		}

		private void TimerTick(TimeSpan ts)
		{
			lblTime.Text = DataUtil.TimespanToTime(ts, ":");
			lblSeconds.Text = ts.Seconds.ToString("00");

			if (Mini != null)
			{
				Mini.SetTimer(ts);
			}
		}

		private void TimerAutoStopped(TimeSpan ts)
		{
			trayIcon.ShowBalloonTip(5000, Messages.SessionPaused, Messages.AutoStopped, ToolTipIcon.Info);

			Show();
		}

		public void TimerStart()
		{
			SessionTimer.Start();

			panStart.Visible = false;
			panPause.Visible = true;

			panNotes.Visible = false;
			panTracking.Visible = true;

			Text = ConfigUtil.GetConfig("Devv.AppName");

			if (Mini != null)
			{
				Mini.Started();
			}
		}

		public void TimerPause()
		{
			SessionTimer.Pause();

			panPause.Visible = false;
			panStart.Visible = true;

			Text = ConfigUtil.GetConfig("Devv.AppName") + " (" + Messages.Paused + ")";

			if (Mini != null)
			{
				Mini.Paused();
			}
		}

		public void TimerSave()
		{
			SessionTimer.PreSave(cboTasks.SelectedItem as Task);

			if (cboTasks.SelectedIndex < 0)
			{
				MessageBox.Show(Messages.PleaseSelectTask, Messages.TimeTracking, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				cboTasks.Focus();

				TimerPause();

				return;
			}

			if (Options.ShowNotes)
			{
				panStart.Visible = false;
				panPause.Visible = true;

				NoteCountdown = 10;
				timerAddNote.Start();

				panTracking.Visible = false;
				panNotes.Visible = true;

				txtNote.Focus();

				Text = ConfigUtil.GetConfig("Devv.AppName") + ": " + Messages.AddNotes;
			}
			else
			{
				AddNote();
			}
		}

		public void TimerReset()
		{
			imgRefresh.Image = Resources.IcoReset16;

			Boolean reset = true;

			if (SessionTimer.Seconds > 60 && MessageBox.Show(Messages.ConfirmReset, Messages.Reset, MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
			{
				reset = false;
			}

			if (reset)
			{
				SessionTimer.Reset();

				lblTime.Text = "00:00";
				lblSeconds.Text = "00";

				panPause.Visible = false;
				panStart.Visible = true;

				Text = ConfigUtil.GetConfig("Devv.AppName");
			}

			imgRefresh.Image = workerLocalCache.IsBusy ? Resources.IcoRefresh16 : Resources.IcoLoading16;
		}

		#endregion

		#region Adding notes and preparing upload

		private void butNoteCancel_Click(object sender, EventArgs e)
		{
			FinishNote(true);
		}

		private void butNoteAdd_Click(object sender, EventArgs e)
		{
			AddNote();
		}

		private void txtNote_KeyDown(object sender, KeyEventArgs e)
		{
			timerAddNote.Stop();

			lblNoteClosing.Visible = false;
			lblNoteClosingIn.Visible = false;
		}

		private void timerAddNote_Tick(object sender, EventArgs e)
		{
			NoteCountdown--;

			if (NoteCountdown == 0)
			{
				AddNote();
			}
			else
			{
				lblNoteClosing.Visible = true;
				lblNoteClosingIn.Visible = true;

				lblNoteClosingIn.Text = NoteCountdown + " " + Messages.Seconds;
			}
		}

		private void AddNote()
		{
			SessionTimer.Save(txtNote.Text);

			FinishNote(false);
		}

		private void FinishNote(Boolean canceled)
		{
			if (canceled)
			{
				TimerPause();
			}
			else
			{
				TimerReset();
			}

			timerAddNote.Stop();

			panNotes.Visible = false;
			panTracking.Visible = true;
		}

		#endregion

		#region Local cache

		private void imgRefresh_Click(object sender, EventArgs e)
		{
			if (!workerLocalCache.IsBusy)
			{
				RefreshLocalCache();
			}
		}

		private void workerLocalCache_DoWork(object sender, DoWorkEventArgs e)
		{
			if (LocalCache.Sessions.Count > 0)
			{
				LocalCache.UploadSavedSessions();
			}

			if (Convert.ToBoolean(e.Argument) || LocalCache.Projects.Count < 1)
			{
				LocalCache.Refresh();
			}
		}

		private void workerLocalCache_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			LocalCacheRefreshed();
		}

		private void RefreshLocalCache()
		{
			if (!Options.IsLoginSet)
			{
				return;
			}

			imgRefresh.Image = Resources.IcoLoading16;
			imgRefresh.Cursor = Cursors.Default;

			workerLocalCache.RunWorkerAsync();
		}

		private void LocalCacheRefreshed()
		{
			if (LocalCache.Projects.Count > 0)
			{
				cboProjects.Enabled = true;
				cboProjects.SelectedIndex = -1;
				cboProjects.DataSource = LocalCache.Projects;

				cboTasks.DataSource = null;

				cboProjects.Enabled = true;
				panSave.Enabled = true;
			}

			for (var i = 0; i < cboProjects.Items.Count; i++)
			{
				if (((Project)cboProjects.Items[i]).Id == Options.LastProjectId)
				{
					cboProjects.SelectedIndex = i;
					SetCurrentProject();

					break;
				}
			}

			if (cboProjects.SelectedIndex < 0)
			{
				cboTasks.Enabled = false;
			}

			imgRefresh.Image = Resources.IcoRefresh16;
			imgRefresh.Cursor = Cursors.Hand;
		}

		#endregion

		#region Tray Menu

		private void trayMenu_Opening(object sender, CancelEventArgs e)
		{
			trayMenuShowMini.Checked = Options.ShowMini;
		}

		private void trayIcon_DoubleClick(object sender, EventArgs e)
		{
			ShowToUser();
		}

		private void trayMenuShow_Click(object sender, EventArgs e)
		{
			ShowToUser();
		}

		private void trayMenuShowMini_Click(object sender, EventArgs e)
		{
			trayMenuShowMini.Checked = !trayMenuShowMini.Checked;

			Options.ShowMini = trayMenuShowMini.Checked;

			if (!Options.ShowMini)
			{
				CloseMini();
			}
			else if (SessionTimer.Running && WindowState == FormWindowState.Minimized)
			{
				ShowMini();
			}
		}

		private void trayMenuTopMost_Click(object sender, EventArgs e)
		{
			trayMenuTopMost.Checked = !trayMenuTopMost.Checked;

			Options.TopMost = trayMenuTopMost.Checked;
			TopMost = trayMenuTopMost.Checked;
		}

		private void trayMenuOptions_Click(object sender, EventArgs e)
		{
			Program.ShowOptionsForm();
		}

		private void trayMenuRules_Click(object sender, EventArgs e)
		{
			Program.ShowRulesForm();
		}

		private void trayMenuDonate_Click(object sender, EventArgs e)
		{
			Process.Start(App.DONATE_URL);
		}

		private void trayMenuExit_Click(object sender, EventArgs e)
		{
			ForceClose = true;

			Close();
		}

		#endregion
	}
}